# AIDL 中的数据结构
在上文我们说到 AIDL 中支持的数据类型,这里我们再回顾一下:
在 Java 层,AIDL 支持以下多种数据类型:
- Java 编程语言中的所有的基本类型(如 int、long、char、boolean 等)
- String 与 CharSequence
- List:List 中的所有元素必须是 AIDL 支持的数据类型,生成的方法旨在使用 List 接口,但另一方实际接收的具体类始终是 ArrayList
- Map:Map 中的所有元素必须是 AIDL 支持的数据类型,不支持泛型 Map(如 Map<String,Integer> 形式的 Map),生成的方法旨在使用 Map 接口,但另一方实际接收的具体类始终是 HashMap
- 生成的方法旨在使用 Map 接口,但另一方实际接收的具体类始终是 HashMap。
- Parcelable 类型
Native 层支持类似的数据类型,这些类型与 Java 层的对应关系如下:
kua
# Native 示例程序
接下来我们就来写一个演示 AIDL 数据类型的 Native层 示例程序:
首先我们在 device/jelly/rice14/
目录下创建如下的文件与文件夹
AIDLCppTypeDemo
├── Android.bp
├── com
│ └── yuandaima
│ ├── IHello.aidl
│ ├── Student.aidl
│ ├── Student.cpp
│ └── Student.h
├── HelloClient.cpp
└── HelloServer.cpp
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
其中的 Student.aidl Student.h Student.cpp
是我们自定义的数据类型,在 AIDL 中自定义数据类型需要继承 Parcelable
:
//Student.h
#ifndef _COM_YUANDAIMA_STUDENT_H
#define _COM_YUANDAIMA_STUDENT_H
#include <android-base/unique_fd.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <binder/Status.h>
#include <utils/RefBase.h>
#include <vector>
using namespace std;
using namespace android;
namespace com {
namespace yuandaima {
class Student : public Parcelable {
public:
Student();
virtual ~Student();
virtual status_t writeToParcel(Parcel* out) const;
virtual status_t readFromParcel(const Parcel* in);
void setAge(int32_t age);
int32_t getAge();
void setName(String16 name);
String16 getName();
private:
String16 mName;
int32_t mAge;
};
}
}
#endif
// Student.cpp
#include "Student.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
using namespace std;
using namespace android;
namespace com {
namespace yuandaima {
Student::Student() {
this->setAge(20);
this->setName(String16("jack"));
}
Student::~Student() {
}
status_t Student::writeToParcel(Parcel* out) const {
status_t err;
err = out->writeString16(mName);
if (err != NO_ERROR) {
return err;
}
err = out->writeInt32(mAge);
if (err != NO_ERROR) {
return err;
}
return NO_ERROR;
}
status_t Student::readFromParcel(const Parcel* in) {
status_t err;
err = in->readString16(&mName);
if (err != NO_ERROR) {
return err;
}
err = in->readInt32(&mAge);
if (err != NO_ERROR) {
return err;
}
return NO_ERROR;
}
int32_t Student::getAge() const {
return mAge;
}
String16 Student::getName() const {
return mName;
}
void Student::setAge(int32_t age) {
mAge = age;
}
void Student::setName(String16 name) {
mName = name;
}
}}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
在 aidl 中我们只需要简单声明即可:
//Student.aidl
package com.yuandaima;
parcelable Student cpp_header "com/yuandaima/Student.h";
1
2
3
4
2
3
4
与 Java 不同的是,我们需要指定对应的头文件。
IHelloService.aidl 中声明了我们 binder 服务的对外接口:
package com.yuandaima;
import com.yuandaima.Student;
interface IHello
{
void hello();
int sum(int x, int y);
int printList(in List<String> strs);
int printMap(in Map maps);
int printStudent(in Student student);
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
接着我们编译 aidl 文件:
# 源码目录下
source build/envsetup.sh
# 选择合适的 product
lunch
# 进入项目目录下
# -I 用于指定我们的在哪里查找 import
aidl-cpp -I . com/yuandaima/IHello.aidl ./ ./IHello.cpp
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
编译后,生成了对应的 h 和 cpp 文件,整个项目结构如下:
AIDLCppTypeDemo
├── Android.bp
├── com
│ └── yuandaima
│ ├── BnHello.h
│ ├── BpHello.h
│ ├── IHello.aidl
│ ├── IHello.h
│ ├── Student.aidl
│ ├── Student.cpp
│ └── Student.h
├── HelloClient.cpp
├── HelloServer.cpp
└── IHello.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
接着服务端类和服务端主程序 HelloServer.cpp
:
#define LOG_TAG "aidl_cpp"
#include <stdlib.h>
#include <utils/RefBase.h>
#include <utils/Log.h>
#include <binder/TextOutput.h>
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "com/yuandaima/IHello.h"
#include "com/yuandaima/BnHello.h"
using namespace android;
class IHelloServer : public com::yuandaima::BnHello
{
public:
binder::Status hello() override
{
ALOGI("hello");
return binder::Status();
}
binder::Status sum(int32_t v1, int32_t v2, int32_t *_aidl_return) override
{
ALOGI("server: sum: %d + %d", v1, v2);
*_aidl_return = v1 + v2;
return binder::Status();
}
binder::Status printList(const ::std::vector<::android::String16>& strs, int32_t* _aidl_return) override
{
for (const auto & str : strs)
{
ALOGI("%s", String8(str).c_str());
}
*_aidl_return = 1;
return binder::Status();
}
binder::Status printMap(const ::android::binder::Map& maps, int32_t* _aidl_return) override
{
for(auto it : maps){
std::string val;
it.second.getString(&val);
ALOGI("key is %s, value is %s", it.first.c_str(), val.c_str());
}
*_aidl_return = 1;
return binder::Status();
}
binder::Status printStudent(const ::com::yuandaima::Student& student, int32_t* _aidl_return) override
{
ALOGI("name is %s, age is %d", String8(student.getName()).c_str(), student.getAge());
*_aidl_return = 1;
return binder::Status();
}
};
int main(int argc, char const *argv[])
{
defaultServiceManager()->addService(String16("IHello"), new IHelloServer());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
接着完成客户端程序 HelloClient.cpp
:
#define LOG_TAG "aidl_cpp"
#include <stdlib.h>
#include <utils/RefBase.h>
#include <utils/Log.h>
#include <binder/TextOutput.h>
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "com/yuandaima/IHello.h"
#include "com/yuandaima/BpHello.h"
#include "com/yuandaima/Student.h"
using namespace android;
int main(int argc, char const *argv[]) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("IHello"));
sp<com::yuandaima::IHello> hello = interface_cast<com::yuandaima::IHello>(binder);
hello->hello();
int ret = 0;
hello->sum(1, 2, &ret);
::std::vector<::android::String16> strs;
int32_t result1;
strs.emplace_back("Hello Binder");
hello->printList(strs, &result1);
::android::binder::Map maps;
maps.insert(::android::binder::Map::value_type("test", ::android::binder::Value("Test")));
int32_t result2;
hello->printMap(maps, &result2);
com::yuandaima::Student student;
int32_t result3;
hello->printStudent(student, &result3);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
最后编译测试:
# 项目目录下执行单编
mm
# 回到系统源码目录
adb push out/target/product/rice14/system/bin/IHelloTypeServer /data/local/tmp
adb push out/target/product/rice14/system/bin/IHelloTypeClient /data/local/tmp
# 进入模拟器 shell 环境
adb shell
cd /data/local/tmp
# 执行服务端
./IHelloTypeServer &
# 执行客户端
./IHelloTypeClient
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
接着查看log:
logcat | grep aidl_cpp
08-07 10:57:44.372 2824 2825 I aidl_cpp: hello
08-07 10:57:44.372 2824 2825 I aidl_cpp: server: sum: 1 + 2
08-07 10:57:44.373 2824 2825 I aidl_cpp: Hello Binder
08-07 10:57:44.373 2824 2825 I aidl_cpp: key is test, value is
08-07 12:04:57.181 10985 10986 I aidl_cpp: hello
08-07 12:04:57.182 10985 10986 I aidl_cpp: server: sum: 1 + 2
08-07 12:04:57.182 10985 10986 I aidl_cpp: Hello Binder
08-07 12:04:57.182 10985 10986 I aidl_cpp: key is test, value is
08-07 12:07:48.053 11334 11335 I aidl_cpp: hello
08-07 12:07:48.053 11334 11335 I aidl_cpp: server: sum: 1 + 2
08-07 12:07:48.054 11334 11335 I aidl_cpp: Hello Binder
08-07 12:07:48.054 11334 11335 I aidl_cpp: key is test, value is
08-07 12:07:48.054 11334 11335 I aidl_cpp: name is jack, age is 20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
从 log 可以看出我们的程序指针成功了。